#include "ImageSequenceExporterDialog.h"
#include "ui_ImageSequenceExporterDialog.h"
#include <filesystem>
#include <QMessageBox>

ImageSequenceExporterDialog::ImageSequenceExporterDialog(const std::string &exportDirectoryPath, MMM::MotionList motions, QWidget* parent) :
    QDialog(parent),
    ui(new Ui::ImageSequenceExporterDialog),
    motions(motions),
    exportDirectoryPath(exportDirectoryPath)
{
    ui->setupUi(this);

    std::tuple<float, float> timestepTuple = MMM::Motion::calculateMinMaxTimesteps(motions);
    float minTimestep = std::get<0>(timestepTuple);
    float maxTimestep = std::get<1>(timestepTuple);

    ui->MinTimestepSpin->setMinimum(minTimestep);
    ui->MaxTimestepSpin->setValue(minTimestep);
    ui->MinTimestepSpin->setMaximum(maxTimestep);
    ui->MaxTimestepSpin->setMinimum(minTimestep);
    ui->MaxTimestepSpin->setValue(maxTimestep);
    ui->MaxTimestepSpin->setMaximum(maxTimestep);
    ui->ConvertToMp4->setChecked(settings.value("exportmotion/imagesequenceAsMP4", QVariant(false)).toBool());

    connect(ui->ExportButton, SIGNAL(clicked()), this, SLOT(exportMotions()));
    connect(ui->CancelButton, SIGNAL(clicked()), this, SLOT(close()));
}

void ImageSequenceExporterDialog::exportMotions() {
    float minTimestep = ui->MinTimestepSpin->value();
    float maxTimestep = ui->MaxTimestepSpin->value();
    int framesPerSecond = ui->FPSSpin->value();

    if (minTimestep > maxTimestep) {
        QMessageBox* msgBox = new QMessageBox(this);
        std::string error_message = "Minimum timestep should be smaller than maximum timestep!";
        msgBox->setText(QString::fromStdString(error_message));
        MMM_INFO << error_message << std::endl;
        msgBox->exec();
    }

    float rate = 1.0f / framesPerSecond;
    int amount = (maxTimestep - minTimestep) / rate;
    int digits = std::to_string(amount).length();
    int number = 0;

    std::string fileName = ui->FileNameEdit->text().toStdString();
    fileName = fileName.empty() ?  "MotionSequence" : fileName;
    std::string path = exportDirectoryPath +  "/" + fileName + "-" + createTimestampString();
    for (float timestep = minTimestep; timestep < maxTimestep; timestep += rate) {
        emit jumpTo(timestep);
        char buffer[100];
        std::snprintf(buffer, sizeof(buffer), (fileName + "_%0" + std::to_string(digits) + "d").c_str(), number++);
        std::string imageName = buffer;
        emit saveScreenshot(timestep, path, imageName);
    }

    std::string convertToMp4FileName = "convert-to-mp4.sh";
    std::string converToMp4FilePath = path + "/" + convertToMp4FileName;
    std::ofstream convertToMp4File(converToMp4FilePath);
    convertToMp4File << "#!/bin/bash" << std::endl;
    convertToMp4File << "FPS=" << std::to_string(framesPerSecond) << std::endl;
    convertToMp4File << "NAME=" << fileName << std::endl;
    convertToMp4File << "DIGITS=" << std::to_string(digits) << std::endl;
    convertToMp4File << std::endl;
    convertToMp4File << "avconv -r $FPS -i $NAME'_%0'$DIGITS'd.png' -b:v 8M $NAME'.mp4'" << std::endl;
    convertToMp4File << std::endl;
    convertToMp4File << "exit" << std::endl;
    convertToMp4File.close();
    int status = std::system(("chmod 755 " + converToMp4FilePath).c_str());
    if (status < 0) {
        MMM_ERROR << "Error: " << strerror(errno) << '\n';
    } else {
        if (ui->ConvertToMp4->isChecked()) {
            MMM_INFO << "Using " << converToMp4FilePath << " to convert image sequence to mp4 via avconv (if installed)" << std::endl;
            status = std::system(("cd " + path + " && ./" + convertToMp4FileName).c_str());
            if (status < 0) {
                MMM_ERROR << "Error: " << strerror(errno) << '\n';
            }
        }
        else {
            MMM_INFO << "The script " << converToMp4FilePath << " can be used to convert the created image sequence to mp4 via avconv (if installed)" << std::endl;
        }

        settings.setValue("exportmotion/imagesequenceAsMP4", QVariant(ui->ConvertToMp4->isChecked()));
    }
    close();
}

std::string ImageSequenceExporterDialog::createTimestampString() {
    auto t = std::time(nullptr);
    auto tm = *std::localtime(&t);
    char buffer[80];
    std::strftime(buffer,sizeof(buffer),"%d.%m.%Y-%H:%M:%S",&tm);
    std::stringstream ss;
    ss << buffer;
    return ss.str();
}

ImageSequenceExporterDialog::~ImageSequenceExporterDialog() {
    delete ui;
}
